package medusa

import (
	"errors"
	"log"
	"math"
)

type result_value struct {
	result interface{}
	err    error
}

func (self *result_value) new_result(result interface{}, err error) *result_value {
	return &(result_value{result, err})
}

//--------
type task struct {
	from        chan *result_value
	method_name string
	args        []interface{}
}

func new_task(method_name string, args []interface{}) *task {

	obj := new(task)

	obj.from = make(chan *result_value)
	obj.method_name = method_name
	obj.args = args

	return obj
}

func (self *task) recv_result() (result interface{}, err error) {
	ret := <-self.from
	close(self.from)
	err = ret.err
	result = ret.result

	return
}

//------------

type Tasklet struct {
	task_name  string
	chan_task  chan *task
	handler    map[string]func(args ...interface{}) (result interface{}, err error)
	task_state StateCounter
	//in method
	tasklet_method_add string "tasklet-add-method"
}

func new_tasklet(task_name string) *Tasklet {

	evp := new(Tasklet)
	evp.Constructor(task_name)

	return evp
}

func (self *Tasklet) Constructor(task_name string) {
	self.task_state.SwicthWorking()
	self.task_name = task_name
	self.chan_task = make(chan *task, math.MaxInt16)
	self.handler = make(map[string]func(args ...interface{}) (result interface{}, err error))
	self.tasklet_method_add = "tasklet-add-method"
	self.handler[self.tasklet_method_add] = func(args ...interface{}) (result interface{}, err error) {
		method_name := args[0].(string)
		method := args[1].(func(args ...interface{}) (result interface{}, err error))
		self.handler[method_name] = method
		result = true
		return
	}

	go func() {
		log.Printf("[Tasklet:%v] work!", self.task_name)
		for {
			task := <-self.chan_task
			if task == nil {
				break //exit signal
			}
			method := self.handler[task.method_name]
			if method != nil {
				result, err := method(task.args...)
				task.from <- &(result_value{result, err})
			} else {
				err := errors.New("[Tasklet:" + self.task_name + "] have no method: '" + task.method_name + "'")
				log.Printf(err.Error())
				task.from <- &(result_value{false, err})
			}
		}
		log.Printf("[Tasklet:%v] free!", self.task_name)
		self.task_state.SwicthClosed()
	}()
}

func (self *Tasklet) AddMethod(method_name string,
	method func(args ...interface{}) (result interface{}, err error)) bool {
	if self.task_state.IsWorking() {
		ret, err := self.CallMethod(self.tasklet_method_add, method_name, method)
		if err == nil {
			return ret.(bool)
		}
		return false
	}

	return false
}

func (self *Tasklet) CallMethod(method string, args ...interface{}) (result interface{}, err error) {

	if self.task_state.IsWorking() {
		task := new_task(method, args)
		self.chan_task <- task

		return task.recv_result()
	}

	return
}

func (self *Tasklet) wait() {
	self.task_state.Wait()
}

func (self *Tasklet) shutdown() {
	if self.task_state.SwicthClosed() {
		self.chan_task <- nil
	}
}

/*
type Tasklet struct {
    handler map[string]func(args ...interface{})
}

func NewTasklet() *Tasklet {
    obj := new(Tasklet)
	obj.Constructor()
	return obj
}

func (self *Tasklet) Constructor() {

}

func (self *Tasklet)Register(msg string, args... interface{}) {

}

//-------------

func Start(task Tasklet) {

}

func RPC(task Tasklet, method string, args... interface{}) {

}

func loop(msg string) {

}
*/
